﻿namespace LogManager.Utils.Optimisation
{
    using NUnit.Framework;
    using System;

    public class TestWeakEventHandler
    {
        [Test]
        public void WeakEventHandler_Ctor_Subscribe_Eventsraised()
        {
            var alarm = new Alarm();
            var sleepy = new Sleepy(alarm);
            alarm.Beep();
            alarm.Beep();

            Assert.AreEqual(2, sleepy.SnoozeCount);
        }

        [Test]
        public void WeakEventHandler_Ctor_ForceCollectReferenced_ReferencesStillExisting()
        {
            var alarm = new Alarm();
            var sleepy = new Sleepy(alarm);

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            alarm.Beep();
            alarm.Beep();

            Assert.AreEqual(2, sleepy.SnoozeCount);
        }

        [Test]
        public void WeakEventHandler_Ctor_CheckShortLifeTime_ShortLifetimeObjectCollected()
        {
            var alarm = new Alarm();
            var sleepyReference = null as WeakReference;
            new Action(() =>
            {
                // Run this in a delegate to that the local variable gets garbage collected
                var sleepy = new Sleepy(alarm);
                alarm.Beep();
                alarm.Beep();
                Assert.AreEqual(2, sleepy.SnoozeCount);
                sleepyReference = new WeakReference(sleepy);
            })();

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Assert.IsNull(sleepyReference.Target);
        }

        public class Alarm
        {
            public EventHandler Beeped;

            public void Beep()
            {
                if (Beeped != null)
                    Beeped(this, new EventArgs());
            }
        }

        public class Sleepy
        {
            public int SnoozeCount { get; private set; }

            public Sleepy(Alarm alarm)
            {
                alarm.Beeped += new WeakEventHandler<EventArgs>(OnBeep).Handler;
            }

            void OnBeep(object sender, EventArgs e)
            {
                SnoozeCount++;
            }
        }
    }
}
